#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <sqlite3.h>
#import <UIKit/UIApplication.h>
#import <LockInfo/Plugin.h>

#import "framework/FWCommon.h"
#import "framework/FWApplication.h"
#import "framework/FWDBAccess.h"
#import "framework/FWPreferences.h"
#import "framework/FWPlugin.h"

#import "PICommon.h"
#import "PIIntegration.h"
#import "PIPlugin.h"
#import "PIContextObject.h"
#import "PITaskStatus.h"
#import "PIContext.h"

#import "PITaskIntegration250.h"
#import "PITask.h"


static NSInteger const kMaxSearchItems = 50;


@implementation PITaskIntegration250


// ******************************************************************************************
#pragma mark -
#pragma mark Fetching a list of Tasks

- (NSMutableString*)basicTaskListSQL:(FWApplication*)app prefs:(FWPreferences*)prefs contexts:(NSString*)contexts key:(NSString*)key parentKey:(NSString*)parentKey search:(NSString*)search
{
    PIPlugin* plugin = (PIPlugin*)app.fwPlugin;
    BOOL debug = plugin.isDebugMode;

    if (debug)
        XLog(@"LI:PITask: Building tasks SQL for prefs %@", prefs);
    
    NSMutableString* allSql = [NSMutableString stringWithCapacity:2000];
    NSInteger utcOffset = [[NSTimeZone systemTimeZone] secondsFromGMTForDate:[NSDate date]];

    [allSql appendFormat:
     @"select T.ZTITLE, T.ZSTARTDATEINTERNAL, T.ZSTARTDATEINCLUDESTIMEINTEGER, T.ZENDDATEINTERNAL, T.ZISALLDAY, T.ZPRIORITYINTEGER, T.ZFCPRIORITY, T.Z_PK, T.ZFLAGGEDINTEGER, T.ZACTIONINTEGER, T.ZPERCENTCOMPLETE, T.ZICON, T.ZHASRECURRENCEINTERNAL, P.ZTITLE, T.ZCHILDCOUNTINTERNAL, T.ZPARENTTASK, K.ZTITLE, K.ZICON, K.ZCOLOR, K.ZTIMEZONE,"
     " case when T.ZCONTEXT in (%@) then %i when T.ZCONTEXT is null then %i else %i end %@,"
     " M.Z_49TAGS2 %@,"
     " T.ZCHILDCOUNTINTERNAL,"
     " T.Z_OPT + K.Z_OPT,"
     " case T.ZPRIORITYINTEGER when 0 then %i else T.ZPRIORITYINTEGER end %@,"
     " case T.ZSTARTDATEINCLUDESTIMEINTEGER when 0 then T.ZSTARTDATEINTERNAL-(%d) else %T.ZSTARTDATEINTERNAL end %@," // If all day then date is UTC - we want local
     " case T.ZISALLDAY when 0 then T.ZENDDATEINTERNAL else T.ZENDDATEINTERNAL-(%d) end %@" // If all day then date is UTC - we want local
     " from ZPICALTASK T"
     " left join ZPICALTASK P on P.Z_PK=T.ZPROJECT"
     " left join ZPICALCALENDAR K on K.Z_PK=T.ZCALENDAR"
     " left join Z_32TAGS M on M.Z_32TASKS=T.Z_PK"
     " where T.Z_ENT=%@ AND T.ZCOMPLETEDDATE is null",
     contexts,
     ContextClassificationInContext,
     ContextClassificationNoContext,
     ContextClassificationOutOfContext,
     kFieldNameContextStatus,
     kFieldNameTagID,
     [prefs intValue:kPIOptionsMissingImportance withDefault:kPIOptionsMissingImportanceDefault],
     kFieldNameImportance,
     utcOffset,
     kFieldNameStartDate,
     utcOffset,
     kFieldNameDueDate,
     DBEntityValue(plugin, kPIEntityTypeTask)];
    
    return allSql;
}


// ******************************************************************************************
#pragma mark -
#pragma mark Augmenting a task - returns a new task

- (NSString*)augmentedBasicTaskSQL:(PITask*)task application:(FWApplication*)app
{
    NSString* sql = [NSString stringWithFormat:
                     @"select 2, N.ZNOTES, T.ZPERCENTCOMPLETE, C.ZTITLE, P.ZTITLE, T.ZCHILDCOUNTINTERNAL,"
                     " group_concat(M.Z_49TAGS2, ','),"
                     " R.ZDAYSOFTHEMONTH, R.ZDAYSOFTHEWEEK, R.ZENDDATE, R.ZFIRSTDAYOFTHEWEEK, R.ZMONTHSOFTHEYEAR, R.ZOCCURRENCECOUNT, R.ZRECURRENCEINTERVAL, R.ZRECURRENCETYPEINTEGER, T.ZRECURRENCETYPEINTEGER, T.ZSENSITIVITY, L.ZTITLE, L.ZLOCATIONDESCRIPTION, L.ZLATITUDE, L.ZLONGITUDE"
                     " from ZPICALTASK T"
                     " left join ZPICALTASK A on T.ZPARENTTASK=A.Z_PK"
                     " left join ZPICONTEXT C on T.ZCONTEXT=C.Z_PK"
                     " left join ZPICALTASK P on T.ZPROJECT=P.Z_PK"
                     " left join Z_32TAGS M on M.Z_32TASKS=T.Z_PK"
                     " left join ZPICALRECURRENCERULE R on R.ZTASK=T.Z_PK"
                     " left join ZNOTESCONTAINER N on N.ZTASK=T.Z_PK"
                     " left join ZPILOCATION L on L.ZTASK=T.Z_PK"
                     " where T.Z_PK = %@"
                     " group by T.Z_PK",
                     task.key];
    
    return sql;
        
}


- (NSString*)addAlarmDataToTaskListSQL:(FWApplication*)app keys:(NSString*)keys prefs:(FWPreferences*)prefs
{
    // If PI not found then do nothing
    PIPlugin* plugin = (PIPlugin*)app.fwPlugin;
    
    NSInteger utcOffset = [[NSTimeZone systemTimeZone] secondsFromGMTForDate:[NSDate date]];
    NSString* alarmsSql = [NSString stringWithFormat:
                           @"select 2, A.ZTASK, A.ZRELATIVETRIGGER, A.ZABSOLUTETRIGGERDATE,"
                           " case T.ZSTARTDATEINCLUDESTIMEINTEGER when 0 then T.ZSTARTDATEINTERNAL-(%d) else %T.ZSTARTDATEINTERNAL end," // If all day then date is UTC - we want local
                           " T.ZISALLDAY,"
                           " 0, null, null, null, null"
                           " from ZPICALALARM A"
                           " join ZPICALTASK T on T.Z_PK=A.ZTASK"
                           " where A.ZTASK in (%@)"
                           " union"
                           " select 2, L.ZTASK, null, null, null, null, "
                           " 1, L.ZLATITUDE, L.ZLONGITUDE, L.ZTITLE, L.ZLOCATIONDESCRIPTION"
                           " from ZPILOCATION L"
                           " where L.ZTASK in (%@) and L.ZLOCATIONNOTIFICATIONRADIUS>0",
                           utcOffset,
                           keys,
                           keys];
    
    return alarmsSql;
}


// ******************************************************************************************
#pragma mark -
#pragma mark Fetching a list of contexts

- (NSString*)numberOfLocationContextsSQL:(FWApplication *)application
{
    NSString* sql = @"select count(*) from ZPILOCATION where ZCONTEXT is not null and ZLOCATIONNOTIFICATIONRADIUS > 0";
    
    return sql;
}


// ******************************************************************************************
#pragma mark -
#pragma mark Fetching a list of contexts

- (NSString*)arrayOfContextsSQL:(FWApplication *)application earliest:(NSDate*)earliest counts:(BOOL)counts
{  
    if (counts) {
        PIPlugin* plugin = (PIPlugin*)application.fwPlugin;

        return [NSString stringWithFormat:
                @"select 2, C.Z_PK, C.ZTITLE, C.ZICON, L.ZLOCATIONNOTIFICATIONRADIUS, count(T.Z_PK)"
                " from ZPICONTEXT C"
                " left join ZPILOCATION L on C.Z_PK=L.ZCONTEXT"
                " left join ZPICALTASK T on C.Z_PK=T.ZCONTEXT and T.ZCOMPLETEDDATE is null and T.Z_ENT=%@"
                "%@"
                " group by C.Z_PK"
                " order by C.ZTITLE",
                [plugin.dbEntityKeys objectForKey:kPIEntityTypeTask],
                earliest ? [NSString stringWithFormat:@" and ifnull(T.ZSTARTDATEINTERNAL,0)<=%i", (int)[earliest timeIntervalSinceReferenceDate]] : @""];

    }
    else {
        return [NSString stringWithString:
                @"select 2, C.Z_PK, C.ZTITLE, C.ZICON, L.ZLOCATIONNOTIFICATIONRADIUS, -1"
                " from ZPICONTEXT C"
                " left join ZPILOCATION L on C.Z_PK=L.ZCONTEXT"
                " group by C.Z_PK"
                " order by C.ZTITLE"];
    }
}


// ******************************************************************************************
#pragma mark -
#pragma mark URL to create a new task

- (NSURL*)urlForNewTask:(NSString*)title importance:(enum PIImportanceType)importance application:(FWApplication*)app info:(NSArray*)info
{
    NSString* encodedTitle = FWXMLEncodeString(title);
    
    // Get the highest current task id
    NSNumber* maxKey = [info objectAtIndex:0];
    NSString* uuid = [info objectAtIndex:1];
    NSString* inbox = FWXMLEncodeString([info objectAtIndex:2]);
    NSString* calendar = FWXMLEncodeString([info objectAtIndex:3]);
    
    NSDateFormatter *format = [[NSDateFormatter alloc] init];
    [format setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"];
    NSString* currentDate = [format stringFromDate:[NSDate date]];

    [format setTimeZone:[NSTimeZone systemTimeZone]];
    [format setDateFormat:@"yyyy-MM-dd'T'00:00:00'Z'"];
    NSString* midnightDate = [format stringFromDate:[NSDate date]];
    [format release];

    NSString* importanceCode;
    switch (importance) {
        case PIImportanceTop:
            importanceCode = @"2"; //top
            break;
        case PIImportanceHigh:
            importanceCode = @"2"; //high
            break;
        case PIImportanceNormal:
            importanceCode = @"1"; //med
            break;
        case PIImportanceLow:
            importanceCode = @"0"; //low
            break;
        default:
            importanceCode = @"1"; //none
            break;
    }
    
//<data><task id="x-coredata://66230855-3499-48F6-B36C-3243C0831871/PICalTask/p244"><modified>2001-01-01T00:00:00Z</modified><startdate/><duedate/><projectName>Inbox</projectName><teamtask>NO</teamtask><completed>NO</completed><percentcomplete>0</percentcomplete><priority>0</priority><priorityandrank/><sensitivity>0</sensitivity><status>0</status><title>!!Action - none - icon</title><note/><color>#000000</color><categories>Internal Task Calendar</categories><repeat>0</repeat><recurrence><data></data></recurrence></task></data>    
    
    CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
    NSString* newUUID = [(NSString*)CFUUIDCreateString(kCFAllocatorDefault, uuidRef) autorelease];
    CFRelease(uuidRef);
    
    NSString* params = [NSString stringWithFormat:@"<data>"
                        "<task id=\"x-coredata://%@/PIEventTask/p%d\">"
                        "<modified>%@</modified>"
                        "<startdate>%@</startdate>"
                        "<duedate>%@</duedate>"
                        "<projectName>%@</projectName>"
                        "<teamtask>NO</teamtask>"
                        "<completed>NO</completed>"
                        "<percentcomplete>0</percentcomplete>"
                        "<priority>%@</priority>"
                        "<priorityandrank/>"
                        "<sensitivity>0</sensitivity>"
                        "<status>0</status>"
                        "<title>%@</title>"
                        "<note/>"
                        "<color>#000000</color>"
                        "<categories>%@</categories>"
                        "<repeat>0</repeat>"
                        "<recurrence><data></data></recurrence>"
                        "</task>"
                        "</data>",
                        newUUID,
                        [maxKey intValue] + 1,
                        currentDate,
                        midnightDate,
                        midnightDate,
                        inbox,
                        importanceCode,
                        encodedTitle,
                        calendar];
    
    NSString* url = [NSString stringWithFormat:@"informant://createTask?%@",
                     FWBase64EncodeString(params)];
    
    return [NSURL URLWithString:url];
}

- (NSString*)infoForNewTaskSQL:(FWApplication*)app
{
    PIPlugin* plugin = (PIPlugin*)app.fwPlugin;
    
    NSMutableString* sql = [NSMutableString stringWithCapacity:100];
    [sql appendString:@"select 2, (select max(Z_PK) from ZPICALTASK), Z_UUID,"];
    [sql appendFormat:@" (select ZTITLE from ZPICALTASK where Z_ENT=%@),",
     [plugin.dbEntityKeys objectForKey:kPIEntityTypeProjectInternal]];
                            
    
    NSInteger taskCalID = [PIIntegration defaultTaskCalendarID:app];
    if (taskCalID > 0)
        [sql appendFormat:@" (select ZTITLE from ZPICALCALENDAR where Z_PK=%d)", taskCalID];
    else
        [sql appendFormat:@" (select ZTITLE from ZPICALCALENDAR where Z_ENT=%@ and ZINTERNALID=%d)",
         [plugin.dbEntityKeys objectForKey:kPIEntityTypeCalendarInternal],
         kPIEntityIDInternalTaskCalendar]; 

    [sql appendString:@" from Z_METADATA where Z_VERSION = (select max(Z_VERSION) from Z_METADATA)"];

    return sql;
}


// ******************************************************************************************
#pragma mark -
#pragma mark Completing a task

- (NSString*)completeTaskSQL:(PITask*)task application:(FWApplication*)app
{
    NSString* sql = [NSString stringWithFormat:
                     @"update ZPICALTASK"
                     " set ZCOMPLETEDDATE=%i"
                     " where Z_PK=%@",
                     (int)[[NSDate date] timeIntervalSinceReferenceDate],
                     task.key];
    
    return sql;
}

@end
